﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Qas.CommonLogic;
using Qas.CommonLogic.BusinessObjects;
using Qas.CommonLogic.BusinessObjects.Graph;
using System.Windows.Forms;
using Qas.CommonLogic.Business_Objects.Graph;

namespace Qas.User.Keepers
{
    public class KeeperDijkstra : AbstractKeeper
    {
        public KeeperDijkstra(Base currentBase)
            : base(currentBase)
        {

        }

        private static PriorityQueue q = new PriorityQueue();

        private static List<State> visitedStates = new List<State>();

        private static State firstVisitedState = new State();


        /// <summary>
        /// Поиск плана
        /// </summary>
        public override List<Plan> Search(List<Task> tasks, List<Condition> initConditions,
            List<Condition> goalConditions)
        {

            //this.initialState = initConditions;
            //this.goalState = goalConditions;

            State initState = new State(goalConditions, 0, null, null);

            List<Condition> completedConditions = new List<Condition>();

            List<Task> completedTasks = new List<Task>();

            Log.currentState = initConditions;

            //Task last = new Task();
            //List<Task> visitedTasks = new List<Task>();

            tasks.Reverse();

            DijkstraSearch(completedConditions, tasks, initState, initConditions, completedTasks);

            List<Plan> plans = new List<Plan>();
            Plan newPlan = new Plan();

            State visitedState = new State(null, 0, null, null);

            while (KeeperDijkstra.q.Count > 0)
            {
                visitedState = (State)(KeeperDijkstra.q.Dequeue());
                if (Condition.Subtraction(initConditions, visitedState.Conditions).Count == 0)
                {
                    newPlan = visitedState.getTasks();


                    newPlan.Tasks.Reverse();
                    ////Фильтрация планов
                    //if (this.filterPlans(newPlan))


                    ////Фильтрация планов
                    //if ((this.filterPlans(newPlan))&&(!plans.Contains(newPlan)))
                    //{
                    //    plans.Add(newPlan);
                    //}
                    //plans.Add(newPlan);

                    if (!plans.Contains(newPlan))
                    {
                        plans.Add(newPlan);
                    }
                }
            }

            //MessageBox.Show("DijkstraSearch");

            return plans;
        }

        private void DijkstraSearch(List<Condition> completedConditions, List<Task> tasks,
                State currentState, List<Condition> goals, List<Task> completedTasks)
        {

            // Ищем все состояния, в которые можем придти
            List<State> nextStates = new List<State>();

            foreach (Task taskItem in tasks)
            {
                if (this.TaskCanBeStartedPost(currentState.Conditions, taskItem))
                {
                    // проверка на то, добавит ли задача новые условия к уже выполненным
                    //if (Condition.Subtraction(taskItem.PreConditions,
                    //    currentState.Conditions).Count == 0)
                    //{
                    //    //если задача не добавляет условий, то не приближает нас к цели
                    //    //ничего не делаем
                    //}
                    //else
                    //{
                    //bool needToCheck = true;
                    //if (completedConditions.Count != 0)
                    //{
                    //    // Сделать "содержит"
                    //    if ((Condition.Subtraction(taskItem.PreConditions,
                    //        completedConditions).Count == 0))
                    //    //if (Condition.Intersection(completedConditions,
                    //    //taskItem.PreConditions).Count != 0)
                    //    {
                    //        //если условия, которые продуцирует задача, уже выполнены, 
                    //        //выполнение задачи не требуется в этом плане
                    //        if ((currentState.Task != null) &&
                    //            (currentState.ContatinsPreCondition(taskItem)))
                    //        // ||(Condition.Subtraction(taskItem.PreConditions,last.PostConditions).Count ==0))
                    //        {
                    //            needToCheck = false;
                    //        }
                    //    }
                    //}

                    // Проверка, чтобы не выполять задачу повторно 
                    if (!completedTasks.Contains(taskItem))
                    {

                        //State curState = new State(currentState);

                        //firstVisitedState = currentState;

                        List<Condition> tmpCond = new List<Condition>();
                        tmpCond.AddRange(currentState.Conditions);


                        //if (firstVisitedState.Tasks != null)
                        //{
                        //    firstVisitedState.Tasks.Add(taskItem);
                        //}

                        foreach (Condition cond in taskItem.PostConditions)
                        {
                            if (tmpCond.Contains(cond))
                            {
                                currentState.Conditions.Remove(cond);
                            }
                        }

                        //completedConditions.AddRange(taskItem.PreConditions);
                        //if ((currentState.PostConditions() == null) || (Condition.Subtraction(
                        //    taskItem.PreConditions, currentState.PostConditions()).Count > 0))
                        //{
                        if (Condition.Subtraction(taskItem.PreConditions, completedConditions).Count > 0)
                        {
                            State availableState = new State(Condition.Summation(
                            currentState.Conditions, taskItem.PreConditions),
                            currentState.Weight + taskItem.Coeff(1.5), currentState,
                            Task.Summation(currentState.Tasks, taskItem));

                            completedTasks.Add(taskItem);

                            if (currentState.Tasks != null)
                            {
                                currentState.Tasks.Add(taskItem);
                            }

                            //запоминаем, что предусловие выполнено
                            // completedConditions.AddRange(taskItem.PreConditions);

                            //visitedTasks.Clear();
                            //visitedTasks.Add(taskItem);

                            visitedStates.Add(availableState);

                            //currentState = availableState;


                            //проверка на достижение целевых условий
                            //if (goals.Count > 0)
                            //{
                            if (Condition.Subtraction(availableState.Conditions, goals).Count == 0)
                            {
                                //KeeperDijkstra.visitedStates.Add(availableState);//Enqueue(availableState);
                                //if (this.checkToAdd(availableState))
                                //{
                                //    q.Enqueue(availableState);
                                //}
                                //break;
                                q.Enqueue(availableState);
                                return;
                            }
                            // }
                            else
                            {
                                if (taskItem.PreConditions.Count == 0)
                                {
                                    q.Enqueue(availableState);
                                    return;
                                }
                            }

                            //if (q.Count > 0)
                            //{
                            //    break;
                            //}



                            List<Task> NewTasks = new List<Task>();
                            NewTasks.AddRange(tasks);
                            //NewTasks.Remove(taskItem);

                            //DijkstraSearch(completedConditions, NewTasks,
                            //availableState, goals, completedTasks);
                            DijkstraSearch(firstVisitedState.Conditions, NewTasks,
                            availableState, goals, completedTasks);


                        }
                        //currentState.Tasks = firstVisitedState.Tasks;
                        //    }
                        // }

                    }
                }
            }
            return;
        }


        private bool filterPlans(Plan plan)
        {
            List<Condition> conditions = new List<Condition>();

            foreach (Task task in plan.Tasks)
            {
                if (task.PreConditions.Count != 0)
                {
                    if (Condition.Subtraction(task.PreConditions, conditions).Count == 0)
                    {
                        return false;
                    }
                    else
                    {
                        conditions.AddRange(task.PreConditions);
                    }
                }
            }
            return true;
        }

        private bool checkToAdd(State state)
        {
            foreach (State qstate in q.getElements())
            {
                if ((Task.Subtraction(qstate.getTasks(),
                    state.getTasks()).Tasks.Count == 0)
                    && (Task.Subtraction(state.getTasks(),
                    qstate.getTasks()).Tasks.Count == 0))
                {
                    return false;
                }
            }
            return true;

        }

        /// <summary>
        /// Проверка на возможность существования задачи при данных постусловиях
        /// </summary>
        private bool TaskCanBeStartedPost(List<Condition> postConditions, Task task)
        {
            foreach (Condition cond in postConditions)
            {
                if (task.PostConditions.Contains(cond))
                {
                    return true;
                }
            }

            return false;
        }




        # region
        /// <summary>
        /// Поиск по алгоритму Дейкстры на состояниях
        /// </summary>
        //private void DijkstraSearch(List<Condition> completedConditions, List<Task> tasks, 
        //    State currentState,List<Condition> goals)
        //{
        //    // Ищем все состояния, в которые можем придти
        //    List<State> nextStates = new List<State>();  

        //    foreach (Task taskItem in tasks)
        //    {
        //        if (this.TaskCanBeStarted(currentState.Conditions, taskItem))
        //        {                    
        //            // проверка на то, добавит ли задача новые условия к уже выполненным
        //            if (Condition.Subtraction(taskItem.PostConditions,
        //                currentState.Conditions).Count == 0)
        //            {
        //                //если задача не добавляет условий, то не приближает нас к цели
        //                //ничего не делаем
        //            }

        //            else
        //            {
        //                State availableState = new State(Condition.Summation(
        //                currentState.Conditions, taskItem.PostConditions),
        //                currentState.Weight + taskItem.Coeff(1), currentState, taskItem);

        //                //запоминаем, что предусловие выполнено
        //                completedConditions.AddRange(taskItem.PreConditions);

        //                //проверка на достижение целевых условий
        //                if (Condition.Subtraction(goals, availableState.Conditions).Count == 0)
        //                {
        //                    //KeeperDijkstra.visitedStates.Add(availableState);//Enqueue(availableState);
        //                    q.Enqueue(availableState);
        //                    return;
        //                }

        //                //bool flag = false;
        //                //если уже были в состоянии, сравниваем веса
        //                //foreach (State st in KeeperDijkstra.visitedStates)
        //                //{
        //                //    if (st == availableState)
        //                //    {
        //                //        if (st.Weight > availableState.Weight)
        //                //        {
        //                //            st.Weight = availableState.Weight;
        //                //            st.previousState = availableState.previousState;
        //                //        }

        //                //        flag = true;
        //                //    }
        //                //}

        //                // если не были - добавляем в список посещенных
        //                //if (flag == false)
        //                //{

        //                //}

        //                List<Task> NewTasks = new List<Task>();
        //                NewTasks.AddRange(tasks);
        //                NewTasks.Remove(taskItem);

        //                DijkstraSearch(completedConditions, NewTasks, availableState, goals);
        //            }
        //        }
        //    }
        //    return;
        //}


        //if (completedConditions.Count != 0)
        //{
        //    if (Condition.Subtraction(completedConditions,
        //    taskItem.PreConditions).Count == 0)
        //        //if (Condition.Intersection(completedConditions,
        //        //taskItem.PreConditions).Count != 0)
        //    {
        //        //если условия, которые продуцирует задача, уже выполнены, 
        //        //выполнение задачи не требуется в этом плане
        //        needToCheck = false;
        //    }
        //}
        //if (needToCheck)
        //{


        //private Plan FindLongest(List<Plan> plans)
        //{
        //    Plan maxPlan = plans.First();
        //    foreach (Plan plan in plans)
        //    {
        //        if (plan.Tasks.Count > maxPlan.Tasks.Count)
        //        {
        //            maxPlan = plan;
        //        }
        //    }
        //    return maxPlan;
        //}
        # endregion
    }
}

//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using Qas.CommonLogic;
//using Qas.CommonLogic.BusinessObjects;
//using Qas.CommonLogic.BusinessObjects.Graph;
//using System.Windows.Forms;
//using Qas.CommonLogic.Business_Objects.Graph;

//namespace Qas.User.Keepers
//{
//    public class KeeperDijkstra : AbstractKeeper
//    {
//        public KeeperDijkstra(Base currentBase)
//            : base(currentBase)
//        {

//        }

//        private static PriorityQueue q = new PriorityQueue();

//        private static List<State> visitedStates = new List<State>();

        
//        /// <summary>
//        /// Поиск плана
//        /// </summary>
//        public override List<Plan> Search(List<Task> tasks, List<Condition> initConditions,
//            List<Condition> goalConditions)
//        {

//            //this.initialState = initConditions;
//            //this.goalState = goalConditions;

//            State initState = new State(goalConditions, 0, null, null);

//            List<Condition> completedConditions =  new List<Condition>();

//            Log.currentState = initConditions;

//            //Task last = new Task();
//            //List<Task> visitedTasks = new List<Task>();

//            tasks.Reverse();

//            DijkstraSearch(completedConditions, tasks, initState, initConditions);

//            List<Plan> plans = new List<Plan>();
//            Plan newPlan = new Plan();
            
//            State visitedState = new State(null, 0, null, null);

//            while (KeeperDijkstra.q.Count > 0)
//            {
//                visitedState = (State)(KeeperDijkstra.q.Dequeue());
//                if (Condition.Subtraction(initConditions, visitedState.Conditions).Count == 0)
//                {
//                    newPlan = visitedState.getTasks();
                    
//                    //Фильтрация планов
//                    if (this.filterPlans(newPlan))
//                    {
//                        plans.Add(newPlan);
//                    }
//                    ///plans.Add(newPlan);
                    
//                    //if (newPlan != null)
//                    //{
//                    //    plans.Add(newPlan);
//                    //}

//                    plans.Add(newPlan);
                    
//                }
//            }

//            //MessageBox.Show("DijkstraSearch");

//            return plans;            
//        }

//        private void DijkstraSearch(List<Condition> completedConditions, List<Task> tasks,
//                State currentState, List<Condition> goals)
//        {

//            // Ищем все состояния, в которые можем придти
//            List<State> nextStates = new List<State>();

//            foreach (Task taskItem in tasks)
//            {
//                if (this.TaskCanBeStartedPost(currentState.Conditions, taskItem))
//                {
//                    // проверка на то, добавит ли задача новые условия к уже выполненным
//                    //if (Condition.Subtraction(taskItem.PreConditions,
//                    //    currentState.Conditions).Count == 0)
//                    //{
//                    //    //если задача не добавляет условий, то не приближает нас к цели
//                    //    //ничего не делаем
//                    //}
//                    //else
//                    //{
//                    //bool needToCheck = true;
//                    //if (completedConditions.Count != 0)
//                    //{
//                    //    // Сделать "содержит"
//                    //    if ((Condition.Subtraction(taskItem.PreConditions,
//                    //        completedConditions).Count == 0))
//                    //    //if (Condition.Intersection(completedConditions,
//                    //    //taskItem.PreConditions).Count != 0)
//                    //    {
//                    //        //если условия, которые продуцирует задача, уже выполнены, 
//                    //        //выполнение задачи не требуется в этом плане
//                    //        if ((currentState.Task != null) &&
//                    //            (currentState.ContatinsPreCondition(taskItem)))
//                    //        // ||(Condition.Subtraction(taskItem.PreConditions,last.PostConditions).Count ==0))
//                    //        {
//                    //            needToCheck = false;
//                    //        }
//                    //    }
//                    //}
//                    if (true)
//                    {
//                        // проверку состояния
//                        //  currentState.Tasks.Add(taskItem);
//                        //
//                        List<Condition> tmpCond = new List<Condition>();
//                        tmpCond.AddRange(currentState.Conditions);

//                        foreach (Condition cond in taskItem.PostConditions)
//                        {
//                            if (tmpCond.Contains(cond))
//                            {
//                                currentState.Conditions.Remove(cond);
//                            }
//                        }
//                        //completedConditions.AddRange(taskItem.PreConditions);
//                            if ((currentState.PostConditions() == null) || (Condition.Subtraction(
//                                taskItem.PreConditions, currentState.PostConditions()).Count > 0))
//                            {
//                        if (Condition.Subtraction(taskItem.PostConditions, completedConditions).Count >0)
//                        {
//                                State availableState = new State(Condition.Summation(
//                                currentState.Conditions, taskItem.PreConditions),
//                                currentState.Weight + taskItem.Coeff(1.5), currentState,
//                                Task.Summation(currentState.Tasks, taskItem));



//                                //запоминаем, что предусловие выполнено
//                                // completedConditions.AddRange(taskItem.PreConditions);

//                                //visitedTasks.Clear();
//                                //visitedTasks.Add(taskItem);

//                                visitedStates.Add(availableState);



//                                //проверка на достижение целевых условий
//                                if (goals.Count > 0)
//                                {
//                                    if (Condition.Subtraction(availableState.Conditions, goals).Count == 0)
//                                    {
//                                        //KeeperDijkstra.visitedStates.Add(availableState);//Enqueue(availableState);
//                                        //if (this.checkToAdd(availableState))
//                                        //{
//                                        //    q.Enqueue(availableState);
//                                        //}
//                                        //break;
//                                        q.Enqueue(availableState);
//                                        return;
//                                    }
//                                }
//                                else
//                                {
//                                    if (taskItem.PreConditions.Count == 0)
//                                    {
//                                        q.Enqueue(availableState);
//                                        return;
//                                    }
//                                }

//                                //if (q.Count > 0)
//                                //{
//                                //    break;
//                                //}



//                                List<Task> NewTasks = new List<Task>();
//                                NewTasks.AddRange(tasks);
//                                NewTasks.Remove(taskItem);

//                                DijkstraSearch(completedConditions, NewTasks,
//                                    availableState, goals);
//                            }
//                    //    }
//                    }

//                    }
//                }
//            }
//            return;
//        }


//        private bool filterPlans(Plan plan)
//        {
//            List<Condition> conditions = new List<Condition>();

//            foreach (Task task in plan.Tasks)
//            {
//                if (task.PreConditions.Count != 0)
//                {
//                    if (Condition.Subtraction(task.PreConditions, conditions).Count == 0)
//                    {
//                        return false;
//                    }
//                    else
//                    {
//                        conditions.AddRange(task.PreConditions);
//                    }
//                }
//            }
//            return true;
//        }

//        private bool checkToAdd(State state)
//        {
//            foreach (State qstate in q.getElements())
//            {
//                if ((Task.Subtraction(qstate.getTasks(),
//                    state.getTasks()).Tasks.Count==0)
//                    &&(Task.Subtraction(state.getTasks(),
//                    qstate.getTasks()).Tasks.Count==0))
//                {
//                    return false;
//                }
//            }
//            return true;

//        }

//        /// <summary>
//        /// Проверка на возможность существования задачи при данных постусловиях
//        /// </summary>
//        private bool TaskCanBeStartedPost(List<Condition> postConditions, Task task)
//        {
//            foreach (Condition cond in postConditions)
//            {
//                if (task.PostConditions.Contains(cond))
//                {
//                    return true;
//                }
//            }

//            return false;
//        }




//# region
//        /// <summary>
//        /// Поиск по алгоритму Дейкстры на состояниях
//        /// </summary>
//        //private void DijkstraSearch(List<Condition> completedConditions, List<Task> tasks, 
//        //    State currentState,List<Condition> goals)
//        //{
//        //    // Ищем все состояния, в которые можем придти
//        //    List<State> nextStates = new List<State>();  

//        //    foreach (Task taskItem in tasks)
//        //    {
//        //        if (this.TaskCanBeStarted(currentState.Conditions, taskItem))
//        //        {                    
//        //            // проверка на то, добавит ли задача новые условия к уже выполненным
//        //            if (Condition.Subtraction(taskItem.PostConditions,
//        //                currentState.Conditions).Count == 0)
//        //            {
//        //                //если задача не добавляет условий, то не приближает нас к цели
//        //                //ничего не делаем
//        //            }

//        //            else
//        //            {
//        //                State availableState = new State(Condition.Summation(
//        //                currentState.Conditions, taskItem.PostConditions),
//        //                currentState.Weight + taskItem.Coeff(1), currentState, taskItem);

//        //                //запоминаем, что предусловие выполнено
//        //                completedConditions.AddRange(taskItem.PreConditions);

//        //                //проверка на достижение целевых условий
//        //                if (Condition.Subtraction(goals, availableState.Conditions).Count == 0)
//        //                {
//        //                    //KeeperDijkstra.visitedStates.Add(availableState);//Enqueue(availableState);
//        //                    q.Enqueue(availableState);
//        //                    return;
//        //                }

//        //                //bool flag = false;
//        //                //если уже были в состоянии, сравниваем веса
//        //                //foreach (State st in KeeperDijkstra.visitedStates)
//        //                //{
//        //                //    if (st == availableState)
//        //                //    {
//        //                //        if (st.Weight > availableState.Weight)
//        //                //        {
//        //                //            st.Weight = availableState.Weight;
//        //                //            st.previousState = availableState.previousState;
//        //                //        }

//        //                //        flag = true;
//        //                //    }
//        //                //}

//        //                // если не были - добавляем в список посещенных
//        //                //if (flag == false)
//        //                //{

//        //                //}

//        //                List<Task> NewTasks = new List<Task>();
//        //                NewTasks.AddRange(tasks);
//        //                NewTasks.Remove(taskItem);

//        //                DijkstraSearch(completedConditions, NewTasks, availableState, goals);
//        //            }
//        //        }
//        //    }
//        //    return;
//        //}


//        //if (completedConditions.Count != 0)
//        //{
//        //    if (Condition.Subtraction(completedConditions,
//        //    taskItem.PreConditions).Count == 0)
//        //        //if (Condition.Intersection(completedConditions,
//        //        //taskItem.PreConditions).Count != 0)
//        //    {
//        //        //если условия, которые продуцирует задача, уже выполнены, 
//        //        //выполнение задачи не требуется в этом плане
//        //        needToCheck = false;
//        //    }
//        //}
//        //if (needToCheck)
//        //{

      
//        //private Plan FindLongest(List<Plan> plans)
//        //{
//        //    Plan maxPlan = plans.First();
//        //    foreach (Plan plan in plans)
//        //    {
//        //        if (plan.Tasks.Count > maxPlan.Tasks.Count)
//        //        {
//        //            maxPlan = plan;
//        //        }
//        //    }
//        //    return maxPlan;
//        //}
//# endregion
//    }
//}